package com.smartalarmclock.Logic;

import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;

import android.content.Context;
import android.util.Log;

import com.smartalarmclock.Model.AlarmClockFactory;
import com.smartalarmclock.Model.AutoResponseFactory;
import com.smartalarmclock.Model.ContactFactory;
import com.smartalarmclock.Model.IAlarmClock;
import com.smartalarmclock.Model.IAutoResponse;
import com.smartalarmclock.Model.IGroup;
import com.smartalarmclock.Model.ILogEntry;
import com.smartalarmclock.Model.IProfile;
import com.smartalarmclock.Model.ISMSMessage;
import com.smartalarmclock.Model.ISingleContact;
import com.smartalarmclock.Model.ITimeFrame;
import com.smartalarmclock.Model.LogEntryFactory;
import com.smartalarmclock.Model.RulesItemFactory;
import com.smartalarmclock.Model.SMSMessageFactory;
import com.smartalarmclock.Model.TimeFrameFactory;
import com.smartalarmclock.Model.Exceptions.ConflictingSchedueledProfilesException;
import com.smartalarmclock.Model.Exceptions.DataEntityDoesNotExistException;
import com.smartalarmclock.Model.Exceptions.InvalidDeleteDataEntityOperationException;
import com.smartalarmclock.Model.Exceptions.InvalidSaveDataEntityOperationException;
import com.smartalarmclock.Model.Exceptions.SMSMessageAlreadyExistsException;
import com.smartalarmclock.Model.IAlarmClock.ShutOffMethod;
import com.smartalarmclock.Model.ITimeFrame.DayInWeek;
import com.smartalarmclock.Model.ITimeFrame.TimeInWeek;

public class AcManager {
	private static AcManager r_Singleton = null;
	private static final String TAG = "AcManager";

	public static AcManager GetInstance()
	{
		if (r_Singleton == null)
		{
			r_Singleton = new AcManager();
		}
		
		return r_Singleton;
	}
	
	// Profiles
	public IProfile GetProfileDetails(Context context, int i_ProfileId)
	{
		RulesItemFactory profilesFactory = new RulesItemFactory();
		
		IProfile profile = null;
		try {
			profile = profilesFactory.GetProfileById(context, i_ProfileId);
		} catch (DataEntityDoesNotExistException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return profile;
	}
	
	public void ModifyProfile(Context context, IProfile i_UpdatedProfile)
	{
		try {
			i_UpdatedProfile.Save(context);
		} catch (InvalidSaveDataEntityOperationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
	
	public void DeleteProfile(Context context, IProfile i_UpdatedProfile)
	{
		try {
			i_UpdatedProfile.Delete(context);
		} catch (InvalidDeleteDataEntityOperationException e) {
		} catch (InvalidSaveDataEntityOperationException e) { }
	}
	
	public void DeleteTimeFrame(Context context, IProfile i_UpdatedProfile, ITimeFrame i_TimeFrame)
	{
		i_UpdatedProfile.DeleteReferenceConnection(context, i_TimeFrame);
	}
	
	public IProfile CreateNewProfile(Context context, String i_ProfileName)
	{
		Log.v("CreateNewProfile", "Now inside creating new profile, making new factories");
		RulesItemFactory profilesFactory = new RulesItemFactory();
		AlarmClockFactory alarmFactory = new AlarmClockFactory();
		AutoResponseFactory autoResponseFactory = new AutoResponseFactory();
		
		boolean isActive = true;
		IAlarmClock alarmClock = alarmFactory.CreateAlarmClock();
		alarmClock.SetRingStatus(true);
		alarmClock.SetShutOffMethod(ShutOffMethod.Snooze);
		IAutoResponse autoResponseMatch = autoResponseFactory.CreateAutoResponse();
		// TODO: this is temporary. Need to get the settings from the Create Profile UI screen
		autoResponseMatch.SetBlocking(true);
		String smsMessageStr = "This is a generic sms. On later versions, this sms will be modified in profile settings.";
		SMSMessageFactory smsFactory = new SMSMessageFactory();
		ISMSMessage smsMessageExist = null;
		try {
			smsMessageExist = smsFactory.GetSMSMessageByMessageString(context, smsMessageStr);
		} catch (DataEntityDoesNotExistException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		ISMSMessage smsMessage;
		if (smsMessageExist == null)
		{
			smsMessage = smsFactory.CreateSMSMessage(smsMessageStr);
			autoResponseMatch.SetSmsToSend(smsMessage);
		}
		
		IAutoResponse autoResponseNotMatch = autoResponseFactory.CreateAutoResponse();
		autoResponseNotMatch.SetBlocking(false);
		// TODO (Ofer): Maybe change default values...
		
		Log.v("CreateNewProfile", "Finished creating factories, creating profile!");
		return profilesFactory.CreateProfile(i_ProfileName, isActive, alarmClock, autoResponseMatch, autoResponseNotMatch);
	}
	
	public ArrayList<ITimeFrame> GetTimeFramesForProfile(Context context, IProfile i_Profile)
	{
		ArrayList<ITimeFrame> TimeFrameList = new ArrayList<ITimeFrame>();
		TimeFrameList.addAll(i_Profile.GetTimeFrames(context));
		return TimeFrameList;
	}
	
	public ITimeFrame GetTimeFrameById(Context context, int i_TimeFrameId)
	{
		TimeFrameFactory timeFrameFactory = new TimeFrameFactory();
		
		ITimeFrame timeFrame = null;
		try {
			timeFrame = timeFrameFactory.GetTimeFrameById(context, i_TimeFrameId);
		} catch (DataEntityDoesNotExistException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return timeFrame;
	}
	
	public ArrayList<IProfile> GetActiveProfiles(Context context)
	{
		RulesItemFactory profilesFactory = new RulesItemFactory();
		
		Set<IProfile> profileSet = profilesFactory.GetActiveProfiles(context);
		
		ArrayList<IProfile> profileList = new ArrayList<IProfile>();
		
		// Set is stored in DB as it is more efficent than a list.
		// However, ArrayAdapter receives a List in the constructor and therefore this transformation is required.
		
		for(IProfile curProfile : profileSet)
		{
			profileList.add(curProfile);
		}
		
		return profileList;
	}
	
	public IProfile GetRunningProfile(Context i_Context, boolean i_CurrentlyEnded) throws ConflictingSchedueledProfilesException
	{
		IProfile runningProfile = null;
		RulesItemFactory profilesFactory = new RulesItemFactory();
		Calendar c = Calendar.getInstance();
		
		DayInWeek dayInWeek = DayInWeek.FromValue(c.get(Calendar.DAY_OF_WEEK));
		
		long timeToDecrease = i_CurrentlyEnded ? 3000 : 0;
		Time time = new Time(c.getTimeInMillis() - timeToDecrease);
		TimeInWeek currentTime = new TimeInWeek(dayInWeek, time);
		
		Log.v(TAG, "Current time: " + currentTime.toString());

		Set<IProfile> matchingProfiles = profilesFactory.GetProfilesByTimeRange(i_Context, currentTime, currentTime);
		
		if (matchingProfiles != null && matchingProfiles.size() > 1) // Only one profile should be active and enabled at a specified time.
		{
			Log.v(TAG, "For some reason, there are more than one profile active at the same time");
			String conflictMessage = ConflictingSchedueledProfilesException.CreateConflictMessage(matchingProfiles, currentTime);
			throw new ConflictingSchedueledProfilesException(conflictMessage);
		}
		
		if (matchingProfiles != null && !matchingProfiles.isEmpty())
		{
			Log.v(TAG, "running profile should be good to go");
			runningProfile = matchingProfiles.iterator().next();
		}
		
		return runningProfile;
	}
	
	// Contacts
	
	public Set<ISingleContact> GetAllSingleContacts(Context context) {
		return new ContactFactory().GetAllSingleContacts(context);
	}
	
	public Set<IGroup> GetAllGroups(Context context) {
		return new ContactFactory().GetAllGroups(context);
	}
	
	public Set<ILogEntry> GetLogEntries(Context context, int i_ContactId) {
		ContactFactory contactFactory = new ContactFactory();
		LogEntryFactory logEntryFactory = new LogEntryFactory();
		ISingleContact contact = null;
		
		if (i_ContactId > 0) {
			try {
				contact = contactFactory.GetSingleContactById(context, i_ContactId);
			} catch (DataEntityDoesNotExistException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			return logEntryFactory.GetLogEntriesBySingleContact(context, contact);
		} else {
			return logEntryFactory.GetLogEntriesByTimeRange(context, new Date(0), new Date());
		}
	}
}
